Public Class Poblacion

    Public listaIndividuos As New ArrayList()
    Public matrizCaminos As Array
    Public vMax As Integer
    Public aptitudPromedio As Decimal
    Public cantCiudades As Decimal
    Public peorTramo As Decimal

    Function calcularAptitud(ByVal unIndividuo As Individuo) As Decimal
        'Despues de muchas pruebas decidimos tomar a todos los invididuos invalidos con aptitud 1
        'y para los validos, hacer vMax menos la sumatoria de las distancias/costos del camino
        'vMax es calculado de forma tal que dicha resta nunca pueda dar negativo.
        'Con esto tenemos la ventaja de que podemos determinar facilmente si hay algun individuo valido en la poblacion
        'ya que de no ser asi, la aptitud promedio sera de 1. Esto lo aprobechamos durante el proceso de seleccion.

        Dim aptitud As Decimal = 0
        Dim costoTramo As Decimal
        Dim distanciaTramo As Decimal
        Dim tipoTramo As Integer

        unIndividuo.Valido = True

        'Almaceno la primer ciudad y el bucle empieza a partir del segundo
        Dim ciudadAnterior As Integer = unIndividuo.Estructura(0)
        Dim tamIndividuo = unIndividuo.Estructura.Length - 1

        For i As Integer = 1 To tamIndividuo
            distanciaTramo = Me.matrizCaminos(ciudadAnterior - 1, unIndividuo.Estructura(i) - 1, 0)
            tipoTramo = Me.matrizCaminos(ciudadAnterior - 1, unIndividuo.Estructura(i) - 1, 1)
            If distanciaTramo = 0 Then
                aptitud = 1
                unIndividuo.Valido = False
                Exit For
            Else
                costoTramo = distanciaTramo / tipoTramo
            End If
            aptitud += costoTramo
            ciudadAnterior = unIndividuo.Estructura(i)
        Next

        If unIndividuo.Valido Then 'En caso de ser valido, tomo la aptitud y lo resto de vmax. En caso contrario, la aptitud sera 1 asi que se deja como esta.
            aptitud = Me.vMax - aptitud
        End If
        Return aptitud
    End Function

    Public Sub CalcularAptitudPoblacion()
        'Aqui se recorre cada individuo y se le aplica la funcion "calcularAptitud"
        If Me.listaIndividuos.Count > 0 Then
            Dim fin As Integer = listaIndividuos.Count - 1
            Me.aptitudPromedio = 0

            For i As Integer = 0 To fin
                Dim individuo As Individuo = Me.listaIndividuos(i)
                If individuo.Aptitud = 0 Then
                    individuo.Aptitud = Me.calcularAptitud(individuo)
                End If
                Me.aptitudPromedio += individuo.Aptitud
            Next
            Me.aptitudPromedio = Me.aptitudPromedio / Me.listaIndividuos.Count
        End If
    End Sub

    Public Function Clone() As Poblacion
        Dim pob As New Poblacion()
        pob.listaIndividuos = Me.listaIndividuos.Clone()
        pob.matrizCaminos = Me.matrizCaminos
        pob.vMax = Me.vMax
        pob.aptitudPromedio = Me.aptitudPromedio
        pob.cantCiudades = Me.cantCiudades
        pob.peorTramo = Me.peorTramo
        Return pob
    End Function

    Public Sub Ordenar()
        'Forma 1
        Dim lista As New ArrayList()
        Dim finPoblacion = Me.listaIndividuos.Count - 1
        lista.Add(Me.listaIndividuos(0))
        Dim indiv As Individuo
        Dim insertado As Boolean
        Dim finLista As Integer = 0

        For i As Integer = 1 To finPoblacion
            indiv = Me.listaIndividuos(i)
            insertado = False
            For j As Integer = 0 To finLista
                If indiv.aptitud >= lista(j).aptitud Then
                    lista.Insert(j, indiv)
                    insertado = True
                    Exit For
                End If
            Next
            If Not insertado Then
                lista.Add(indiv)
            End If
            finLista += 1
        Next
        Me.listaIndividuos = lista
    End Sub
End Class
